// File: lf_queue_benchmark.cpp
#include <atomic>
#include <chrono>
#include <thread>
#include <vector>

#include <benchmark/benchmark.h>

#include "ms_lock_free_queue.hpp"
#include "spsc_ring_buffer.hpp"
#include "mpsc_ring_buffer.hpp"
#include "lcr_queue.hpp"

namespace Common::Benchmarks {

  /**
   * @brief 基准测试结果封装。
   */
  struct BenchmarkResult {
    std::size_t total_operations = 0;          ///< 总操作次数（入队 + 出队）
    std::chrono::nanoseconds duration{};       ///< 总耗时
    double throughput_ops_per_sec = 0.0;       ///< 吞吐量（操作/秒）
  };

  /**
   * @brief 计算吞吐量的辅助函数。
   */
  inline auto makeResult(std::size_t ops,
                         std::chrono::nanoseconds elapsed) -> BenchmarkResult {
    BenchmarkResult result{};
    result.total_operations = ops;
    result.duration = elapsed;
    if (elapsed.count() > 0) {
      const double seconds = static_cast<double>(elapsed.count()) * 1e-9;
      result.throughput_ops_per_sec = static_cast<double>(ops) / seconds;
    }
    return result;
  }

  /**
   * @brief 运行 SPSC 队列基准测试。
   *
   * @tparam QueueSPSC 队列类型，需满足 push/pop 接口。
   * @param iterations 每个线程执行的操作次数。
   * @return 基准测试结果。
   *
   * @note
   *  - 生产者与消费者各一条线程。
   *  - 通过忙等（spin）保持无锁特性。
   */
  template<typename QueueSPSC>
  auto runSPSCProducerConsumerBenchmark(std::size_t iterations) -> BenchmarkResult {
    QueueSPSC queue(iterations * 2);

    std::atomic<bool> start_flag{false};
    std::atomic<std::size_t> produced{0};
    std::atomic<std::size_t> consumed{0};

    std::thread producer([&]() {
      while (!start_flag.load(std::memory_order_acquire)) {
        std::this_thread::yield();
      }
      for (std::size_t i = 0; i < iterations; ++i) {
        while (!queue.push(static_cast<typename QueueSPSC::value_type>(i))) {
          std::this_thread::yield();
        }
        produced.fetch_add(1, std::memory_order_relaxed);
      }
    });

    std::thread consumer([&]() {
      typename QueueSPSC::value_type value{};
      while (!start_flag.load(std::memory_order_acquire)) {
        std::this_thread::yield();
      }
      for (std::size_t i = 0; i < iterations; ++i) {
        while (!queue.pop(value)) {
          std::this_thread::yield();
        }
        consumed.fetch_add(1, std::memory_order_relaxed);
      }
    });

    const auto start = std::chrono::steady_clock::now();
    start_flag.store(true, std::memory_order_release);

    producer.join();
    consumer.join();

    const auto end = std::chrono::steady_clock::now();
    const auto ops = produced.load(std::memory_order_relaxed) +
                     consumed.load(std::memory_order_relaxed);
    return makeResult(ops, end - start);
  }

  /**
   * @brief 运行 MPSC 队列基准测试。
   *
   * @tparam QueueMPSC 队列类型，需满足 enqueue/dequeue 接口。
   * @param producer_threads 生产者线程数量。
   * @param iterations_per_producer 每个生产者的操作次数。
   * @return 基准测试结果。
   */
  template<typename QueueMPSC>
  auto runMPSCProducerConsumerBenchmark(std::size_t producer_threads,
                                        std::size_t iterations_per_producer) -> BenchmarkResult {
    QueueMPSC queue(producer_threads * iterations_per_producer * 2);

    std::atomic<bool> start_flag{false};
    std::atomic<std::size_t> produced{0};
    std::atomic<std::size_t> consumed{0};

    std::vector<std::thread> producers;
    producers.reserve(producer_threads);
    for (std::size_t p = 0; p < producer_threads; ++p) {
      producers.emplace_back([&, p]() {
        while (!start_flag.load(std::memory_order_acquire)) {
          std::this_thread::yield();
        }
        for (std::size_t i = 0; i < iterations_per_producer; ++i) {
          auto value = static_cast<typename QueueMPSC::value_type>(p * iterations_per_producer + i);
          while (!queue.enqueue(value)) {
            std::this_thread::yield();
          }
          produced.fetch_add(1, std::memory_order_relaxed);
        }
      });
    }

    std::thread consumer([&]() {
      typename QueueMPSC::value_type value{};
      while (!start_flag.load(std::memory_order_acquire)) {
        std::this_thread::yield();
      }
      const std::size_t total_expected = producer_threads * iterations_per_producer;
      while (consumed.load(std::memory_order_relaxed) < total_expected) {
        if (queue.dequeue(value)) {
          consumed.fetch_add(1, std::memory_order_relaxed);
        } else {
          std::this_thread::yield();
        }
      }
    });

    const auto start = std::chrono::steady_clock::now();
    start_flag.store(true, std::memory_order_release);

    for (auto &t : producers) {
      t.join();
    }
    consumer.join();

    const auto end = std::chrono::steady_clock::now();
    const auto ops = produced.load(std::memory_order_relaxed) +
                     consumed.load(std::memory_order_relaxed);
    return makeResult(ops, end - start);
  }

  /**
   * @brief 运行有界 MPMC 队列基准测试（例如 LCRQueue）。
   *
   * @tparam QueueMPMC 队列类型，需满足带容量构造与 enqueue/dequeue 接口。
   * @param producer_threads 生产者线程数。
   * @param consumer_threads 消费者线程数。
   * @param iterations_per_producer 每个生产者执行的操作次数。
   * @return 基准测试结果。
   */
  template<typename QueueMPMC>
  auto runBoundedMPMCBenchmark(std::size_t producer_threads,
                               std::size_t consumer_threads,
                               std::size_t iterations_per_producer) -> BenchmarkResult {
    QueueMPMC queue(producer_threads * iterations_per_producer * 2);

    std::atomic<bool> start_flag{false};
    std::atomic<std::size_t> produced{0};
    std::atomic<std::size_t> consumed{0};

    std::vector<std::thread> producers;
    producers.reserve(producer_threads);
    for (std::size_t p = 0; p < producer_threads; ++p) {
      producers.emplace_back([&, p]() {
        while (!start_flag.load(std::memory_order_acquire)) {
          std::this_thread::yield();
        }
        for (std::size_t i = 0; i < iterations_per_producer; ++i) {
          auto value = static_cast<typename QueueMPMC::value_type>(p * iterations_per_producer + i);
          while (!queue.enqueue(value)) {
            std::this_thread::yield();
          }
          produced.fetch_add(1, std::memory_order_relaxed);
        }
      });
    }

    std::vector<std::thread> consumers;
    consumers.reserve(consumer_threads);
    const std::size_t total_expected = producer_threads * iterations_per_producer;
    for (std::size_t c = 0; c < consumer_threads; ++c) {
      consumers.emplace_back([&]() {
        typename QueueMPMC::value_type value{};
        while (!start_flag.load(std::memory_order_acquire)) {
          std::this_thread::yield();
        }
        while (consumed.load(std::memory_order_relaxed) < total_expected) {
          if (queue.dequeue(value)) {
            consumed.fetch_add(1, std::memory_order_relaxed);
          } else {
            std::this_thread::yield();
          }
        }
      });
    }

    const auto start = std::chrono::steady_clock::now();
    start_flag.store(true, std::memory_order_release);

    for (auto &t : producers) {
      t.join();
    }
    for (auto &t : consumers) {
      t.join();
    }

    const auto end = std::chrono::steady_clock::now();
    const auto ops = produced.load(std::memory_order_relaxed) +
                     consumed.load(std::memory_order_relaxed);
    return makeResult(ops, end - start);
  }

  /**
   * @brief 运行无界 MPMC 队列基准测试（例如 MSLockFreeQueue）。
   *
   * @tparam QueueMPMC 队列类型，需提供默认构造与 enqueue/dequeue 接口。
   * @param producer_threads 生产者线程数。
   * @param consumer_threads 消费者线程数。
   * @param iterations_per_producer 每个生产者执行的操作次数。
   * @return 基准测试结果。
   */
  template<typename QueueMPMC>
  auto runUnboundedMPMCBenchmark(std::size_t producer_threads,
                                 std::size_t consumer_threads,
                                 std::size_t iterations_per_producer) -> BenchmarkResult {
    QueueMPMC queue;

    std::atomic<bool> start_flag{false};
    std::atomic<std::size_t> produced{0};
    std::atomic<std::size_t> consumed{0};

    std::vector<std::thread> producers;
    producers.reserve(producer_threads);
    for (std::size_t p = 0; p < producer_threads; ++p) {
      producers.emplace_back([&, p]() {
        while (!start_flag.load(std::memory_order_acquire)) {
          std::this_thread::yield();
        }
        for (std::size_t i = 0; i < iterations_per_producer; ++i) {
          auto value = static_cast<typename QueueMPMC::value_type>(p * iterations_per_producer + i);
          queue.enqueue(value);
          produced.fetch_add(1, std::memory_order_relaxed);
        }
      });
    }

    std::vector<std::thread> consumers;
    consumers.reserve(consumer_threads);
    const std::size_t total_expected = producer_threads * iterations_per_producer;
    for (std::size_t c = 0; c < consumer_threads; ++c) {
      consumers.emplace_back([&]() {
        typename QueueMPMC::value_type value{};
        while (!start_flag.load(std::memory_order_acquire)) {
          std::this_thread::yield();
        }
        while (consumed.load(std::memory_order_relaxed) < total_expected) {
          if (queue.dequeue(value)) {
            consumed.fetch_add(1, std::memory_order_relaxed);
          } else {
            std::this_thread::yield();
          }
        }
      });
    }

    const auto start = std::chrono::steady_clock::now();
    start_flag.store(true, std::memory_order_release);

    for (auto &t : producers) {
      t.join();
    }
    for (auto &t : consumers) {
      t.join();
    }

    const auto end = std::chrono::steady_clock::now();
    const auto ops = produced.load(std::memory_order_relaxed) +
                     consumed.load(std::memory_order_relaxed);
    return makeResult(ops, end - start);
  }

} // namespace Common::Benchmarks

/**
 * @brief Google Benchmark 钩子：SPSC 环形缓冲队列。
 */
template<typename Queue>
static void BM_SPSCQueue(benchmark::State &state) {
  const std::size_t iterations = static_cast<std::size_t>(state.range(0));
  for (auto _ : state) {
    auto result = Common::Benchmarks::runSPSCProducerConsumerBenchmark<Queue>(iterations);
    state.SetIterationTime(static_cast<double>(result.duration.count()) * 1e-9);
    state.counters["TotalOps"] = static_cast<double>(result.total_operations);
    state.counters["ThroughputOpsPerSec"] = result.throughput_ops_per_sec;
  }
}

/**
 * @brief Google Benchmark 钩子：MPSC 环形缓冲队列。
 */
template<typename Queue>
static void BM_MPSCQueue(benchmark::State &state) {
  const std::size_t producers = static_cast<std::size_t>(state.range(0));
  const std::size_t iterations_per_producer = static_cast<std::size_t>(state.range(1));
  for (auto _ : state) {
    auto result = Common::Benchmarks::runMPSCProducerConsumerBenchmark<Queue>(producers,
                                                                              iterations_per_producer);
    state.SetIterationTime(static_cast<double>(result.duration.count()) * 1e-9);
    state.counters["TotalOps"] = static_cast<double>(result.total_operations);
    state.counters["ThroughputOpsPerSec"] = result.throughput_ops_per_sec;
  }
}

/**
 * @brief Google Benchmark 钩子：有界 MPMC 队列（如 LCRQueue）。
 */
template<typename Queue>
static void BM_BoundedMPMCQueue(benchmark::State &state) {
  const std::size_t producers = static_cast<std::size_t>(state.range(0));
  const std::size_t consumers = static_cast<std::size_t>(state.range(1));
  const std::size_t iterations_per_producer = static_cast<std::size_t>(state.range(2));
  for (auto _ : state) {
    auto result = Common::Benchmarks::runBoundedMPMCBenchmark<Queue>(producers,
                                                                     consumers,
                                                                     iterations_per_producer);
    state.SetIterationTime(static_cast<double>(result.duration.count()) * 1e-9);
    state.counters["TotalOps"] = static_cast<double>(result.total_operations);
    state.counters["ThroughputOpsPerSec"] = result.throughput_ops_per_sec;
  }
}

/**
 * @brief Google Benchmark 钩子：无界 MPMC 队列（如 MSLockFreeQueue）。
 */
template<typename Queue>
static void BM_UnboundedMPMCQueue(benchmark::State &state) {
  const std::size_t producers = static_cast<std::size_t>(state.range(0));
  const std::size_t consumers = static_cast<std::size_t>(state.range(1));
  const std::size_t iterations_per_producer = static_cast<std::size_t>(state.range(2));
  for (auto _ : state) {
    auto result = Common::Benchmarks::runUnboundedMPMCBenchmark<Queue>(producers,
                                                                       consumers,
                                                                       iterations_per_producer);
    state.SetIterationTime(static_cast<double>(result.duration.count()) * 1e-9);
    state.counters["TotalOps"] = static_cast<double>(result.total_operations);
    state.counters["ThroughputOpsPerSec"] = result.throughput_ops_per_sec;
  }
}

/* 注册基准 */
BENCHMARK_TEMPLATE(BM_SPSCQueue, Common::SPSCRingBuffer<int>)
    ->Arg(1 << 14) /* 单次迭代入队/出队次数 */
    ->UseManualTime();

BENCHMARK_TEMPLATE(BM_MPSCQueue, Common::MPSCRingBuffer<int>)
    ->Args({4, 1 << 12}) /* {生产者数量, 单生产者操作数} */
    ->UseManualTime();

BENCHMARK_TEMPLATE(BM_BoundedMPMCQueue, Common::LCRQueue<int>)
    ->Args({4, 4, 1 << 11}) /* {生产者数, 消费者数, 单生产者操作数} */
    ->UseManualTime();

BENCHMARK_TEMPLATE(BM_UnboundedMPMCQueue, Common::MSLockFreeQueue<int>)
    ->Args({4, 4, 1 << 11})
    ->UseManualTime();

/* Google Benchmark 提供的 main 函数入口 */
BENCHMARK_MAIN();